/*!
* @file Vector3d.h
* @brief 三维矢量（点）
* @date 2024/9/11
*/
#pragma once

#include <cmath>
#include <cfloat>
#include <limits>
#include "Vector2D.h"

namespace data
{
/*!
* @brief 三维矢量
*/
template<class float_type>
class Vector3
{
public:
    using traits_type = std::numeric_limits<float_type>;

    /*!
    * @brief 开放成员
    */
    float_type x; /**< x-coordinate */
    float_type y; /**< y-coordinate */
    float_type z; /**< z-coordinate */

    /*!
    * @brief 矢量构造
    */
    Vector3(float_type fx = 0.0, float_type fy = 0.0, float_type fz = 0.0) : x(fx), y(fy), z(fz) {}
    explicit Vector3(const Vector2<float_type>& v, float_type fz) : x(v.x), y(v.y), z(fz) {}
    template<typename R>
    explicit Vector3(const Vector3<R>& v) : x(v.x), y(v.y), z(v.z) {}
    Vector3(const Vector3& v) = default;
    Vector3(Vector3&& v) noexcept = default;
    ~Vector3() = default;

    /*!
    * @brief 矢量运算
    */
    Vector3& operator=(const Vector3& v) = default;
    Vector3& operator=(Vector3 && v) noexcept = default;
    Vector3 operator+(const Vector3& v) const;
    Vector3 operator&(const Vector3& v) const;
    Vector3 operator-(const Vector3& v) const;
    Vector3 operator-() const;
    Vector3& operator+=(const Vector3& v);
    Vector3& operator-=(const Vector3& v);
    Vector3 operator*(float_type scale) const;
    Vector3 operator/(float_type div) const;
    Vector3& operator*=(float_type scale);
    Vector3& operator/=(float_type div);
    bool operator==(const Vector3& v) const;
    bool operator!=(const Vector3& v) const;

    /// 点积
    float_type operator*(const Vector3& v) const;
    float_type Dot(const Vector3& v) const;

    /// 叉积
    Vector3 operator%(const Vector3& v) const;
    Vector3 Cross(const Vector3& v) const;

    /*!
    * @brief 矢量操作
    */
    Vector3& ScaleX(float_type f);
    Vector3& ScaleY(float_type f);
    Vector3& ScaleZ(float_type f);
    Vector3& Scale(float_type fX, float_type fY, float_type fZ);
    Vector3& MoveX(float_type f);
    Vector3& MoveY(float_type f);
    Vector3& MoveZ(float_type f);
    Vector3& Move(float_type fX, float_type fY, float_type fZ);
    Vector3& RotateX(float_type f);
    Vector3& RotateY(float_type f);
    Vector3& RotateZ(float_type f);
    Vector3& Set(float_type fX, float_type fY, float_type fZ);

    Vector2<float_type> Vec2() const;
    float_type Length() const;
    float_type Sqr() const;
    Vector3& Normalize();
    Vector3 Normalized() const;

    float_type GetAngle(const Vector3& v) const;
    float_type Distance(const Vector3& p) const;
    bool IsZero() const;
    bool IsEqual(const Vector3& p, float_type tol) const;
    bool IsParallel(const Vector3& v, float_type tol) const;
    bool IsNormal(const Vector3& v, float_type tol) const;

    /// 线投影
    Vector3 ProjectToLine(const Vector3& base, const Vector3& dir) const;
    /// 点线距离
    float_type DistanceToLine(const Vector3& base, const Vector3& dir) const;
    /// 面投影
    Vector3 ProjectToPlane(const Vector3& base, const Vector3& normal);
    /// 点面距离
    float_type DistanceToPlane(const Vector3& base, const Vector3& normal) const;

    /*!
    * @brief 类型转换
    */
    template<typename R>
    operator Vector3<R>() const { return Vector3<R>(x, y, z); }

    /*!
    * @brief 文本信息输出
    */
    friend std::ostream& operator<< (std::ostream& stream, const Vector3& v)
    {
        return stream << "{ x: " << v.x << ", y: " << v.y << ", z: " << v.z << " }";
    }
};

using Vector3f = Vector3<float>;
using Vector3d = Vector3<double>;

}  // namespace data
